package PrjConf

import (
	"dgo/goutils/dnet"
	"dgo/goutils/utils"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"io/ioutil"
	"net/http"
	"os"
	"reflect"
	"unsafe"
)

var (
	BUILD_TIME string
	APP_TYPE   string // APP 类型, 如果有值 APP_ID中会出现
	APP_UUID   string // 唯一ID, 机器码, 有一些设备,可能每次都会变化, 程序一旦启动 不能进行变化
)

func GetUrl(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode == 404 || resp.StatusCode == 503 {
		return nil, errors.New(resp.Status)
	}

	body, err := ioutil.ReadAll(resp.Body)
	return body, err

}

func MakeAppId(apptype string, prefix string) string {
	var sb utils.BytesBuilder
	if len(apptype) > 0 {
		sb.AppendStr(apptype).AppendStr("-")
	}
	if len(prefix) > 0 {
		sb.AppendStr(prefix).AppendStr("-")
	}

	sb.Appendf("%X", utils.CRC24QBuf([]byte(dnet.GetFirstMacAsStringEx())))

	return utils.Trim(sb.String())
}

func AssignObjFromSV(obj interface{}, sv *wrapper.SuperValue) error {
	v := reflect.ValueOf(obj)
	vk := v.Kind()
	if vk != reflect.Ptr {
		return fmt.Errorf("obj必须为结构体指针")
	}

	elem := v.Elem()
	vtype := elem.Type()
	for i := 0; i < elem.NumField(); i++ {
		fd := vtype.Field(i)
		elemfd := elem.Field(i)
		str := fd.Tag.Get("field")
		if len(str) == 0 {
			str = fd.Tag.Get("id")
		}
		if len(str) == 0 {
			str = fd.Name
		}

		v := sv.FindByPath(str)
		if v == nil {
			continue
		}

		kd := elemfd.Kind()
		if kd == reflect.String {
			*(*string)(unsafe.Pointer(elemfd.Addr().Pointer())) = v.String()
		} else if kd == reflect.Float64 || kd == reflect.Float32 {
			elemfd.SetFloat(v.Float64())
		} else if kd == reflect.Int64 || kd == reflect.Int || kd == reflect.Int8 ||
			kd == reflect.Int16 {
			elemfd.SetInt(v.Int64())
		} else if kd == reflect.Uint32 {
			elemfd.SetUint(uint64(v.Int64()))
		} else {
			if fd.Type == utils.REFLECT_TYPE_TIME {
				elemfd.Set(reflect.ValueOf(v.DateTime()))
			}
			fmt.Fprintf(os.Stderr, "unkown type:%v", fd.Type)
		}
	}
	return nil
}

func ReloadPojoListFromSV(pojoMap *utils.GSyncMapGroup, json *wrapper.SuperValue, newPojo func() interface{},
	keyfn func(key string, itm *wrapper.SuperValue) interface{}, afterup func(val interface{})) {

	checkv := newPojo()
	loadfieldname := utils.GetObjectFieldNameByTag(checkv, "type", "loadflag")
	if len(loadfieldname) > 0 {
		pojoMap.Range(func(key, value interface{}) bool {
			utils.SetObjectVal(value, loadfieldname, -1)
			return true
		})
	}

	json.Range(func(key string, val *wrapper.SuperValue) bool {
		var mapkey interface{}
		if keyfn != nil {
			mapkey = keyfn(key, val)
		} else {
			mapkey = key
		}
		v := pojoMap.LoadOrStoreFunc(mapkey, newPojo, nil)
		AssignObjFromSV(v, val)
		utils.SetObjectVal(v, loadfieldname, 0)
		return true
	})

	if len(loadfieldname) > 0 {
		pojoMap.Range(func(key, value interface{}) bool {
			if utils.GetObjectVal(value, loadfieldname, 0) == -1 {
				pojoMap.Remove(key)
			}
			return true
		})
	}
}

func GetCommandLineFromJSON(json *wrapper.SuperValue) (rval string) {
	if json == nil {
		return ""
	}
	if json.IsObject() {
		cmdtype := json.AsString("cmdtype", "")
		if len(cmdtype) > 0 {
			rval = cmdtype + json.AsString("cmdline", "")
			ex := json.Find("ex")
			if ex != nil {
				str := string(ex.AsJSONString(false))
				if len(str) > 0 {
					url := utils.QueryEscapeUrl(str)
					rval += "/" + url
				}
			}
		} else {

			rval = json.AsString("cmdline", "")
			ex := json.Find("ex")
			if ex != nil {
				str := ex.AsJSONString(false)
				if len(str) > 0 {
					url := utils.QueryEscapeUrl(str)
					rval += "/" + url
				}
			}
		}
	} else {
		rval = json.String()
	}
	return
}
